home *** CD-ROM | disk | FTP | other *** search
- From: Dietmar Kuehl <Dietmar.Kuehl@uni-konstanz.de>
- Message-ID: <199602112213.XAA12589@uzwil>
- X-Original-Date: Sun, 11 Feb 1996 23:13:09 +0100 (MET)
- Path: in2.uu.net!bounce-back
- Date: 12 Feb 96 07:17:28 GMT
- Approved: fjh@cs.mu.oz.au
- Organization: -
- Subject: Re: proposal: renew & relocator member fn
- Reply-To: Dietmar.Kuehl@uni-konstanz.de
- Newsgroups: comp.std.c++
- X-Mailer: ELM [version 2.4 PL25]
- X-Auth: PGPMoose V1.1 PGP comp.std.c++
- iQBFAgUBMR7zmeEDnX0m9pzZAQGYnAF/djDtEyTa/8neazM0wpt9FcSbPYSBla6e
- xxPNd5Md0lKRSUHcYw/h+26zMkXWHyDW
- =5vRa
-
- Hi,
-
- Gregory Bond <gnb@bby.com.au> wrote:
- > People often ask for a "renew[]" operator to complement "new[]" in the
- > same way realloc() complements malloc(). Of course the problem there
- > is contructing the new objects and destructing the old ones, so a
- > whole bunch of code gets written to do a new[], a bunch of assigns and a
- > delete[]. This (or the moral equivalent using malloc(), placement new
- > and delete) is especially prevalent inside container classes such
- > as STL.
-
- I can only see one (minor) advantage to use 'realloc()' instead of a
- more flexible method (see below): You can make use of the size of
- memory object known to the memory system. If you accept that you
- "waste" the storage to remember the actual size of a memory object you
- can do without 'renew' or 'realloc()' using a "traits" mechanism.
-
- > I was thinking about the efficiency concerns here. For what is
- > conceptually a simple operation, three calls are made - a default
- > ctor, a copy ctor and a dtor. The copy ctor may potentially have to
-
- Most likely, two operations are to be made: a placement call to the
- ctor and a call to the dtor. It should be avoided to construct an
- object twice (I'm not sure but I think constructing an object twice
- results in undefined behavior)!
-
- > allocate and deep-copy extensive data structures, so this can be very
- > expensive, especially when shallow copy would be sufficient if the
- > copy-ctor could KNOW that the source object was about to be destroyed.
- >
- > So it seems to me that a combination of copy constructor and destructor
- > could be used in these circumstances to "relocate" an object. You
- > could call this special member a "relocator". This could offer
- > substantial efficiency gains, especially in situations like
- > vector<vector<A> >.
-
- I agree with you that the copy constructor is sometimes a bad choice to
- be used for doing a reallocation. A more appropriate constructor, a
- "move constructor", can often be used: This constructor initializes one
- object by moving all relevant members from one object into another one
- leaving the original object in a state which is useless except for
- destruction (this sometimes involves additional operations like setting
- pointers to zero). This makes exactly use of the knowledge you want to
- use for your "relocator" function. All what remains is to tell a
- container class which does the actual relocation that it should use a
- pair of "move constructor" and destructor calls. One possibility to do
- so is to gather this information and other relevant information in a
- "Traits" template argument to the container which contains 'static'
- member functions to be used for certain operations. Here are general
- and specific "traits" which define a method for a movement:
-
- // The general 'move_traits' are useful for all classes defining
- // a copy constructor. Classes with other needs can define
- // specializations of this struct.
-
- template <class T>
- struct move_traits
- {
- T *move(T &source, void *target)
- {
- T *rc = new(target) T(source);
- source.~T();
- return rc;
- }
- };
-
- class Moveable
- {
- public:
- // pass a 'bool' for a different signature than the copy ctor
- Moveable(Moveable &, bool);
- // ...
- };
-
- struct move_traits<Moveable>
- {
- T *move(T &source, void *target)
- {
- T *rc = new(target) T(source, true);
- source.~T();
- return rc;
- }
- };
-
- This solution of the move problem might require more work when
- implementing a "moveable" class than the 'renew' approach. But is does
- not require an extension of the language which is large enough without
- 'renew'. A problem might be that the STL containers do not use this
- approach to move an object but I think this could be solved easily if
- it is really desired. For an example of a container class (which is not
- completely finished) using such an approach you can have a look at
-
- http://www.informatik.uni-konstanz.de/~kuehl/c++/array.h.html
-
- Another approach is to use smart-pointers: Use a smart-pointer with
- "move on copy" semantic (like 'auto_ptr'; is it defined like this in
- the current version of the DWP?) or a "copy on write" semantic
- involving some reference counting. Instead of copying the whole object,
- a pointer to the object is copied. Unfortunately, the Standard Library
- does not include a complete set of smart pointers. The only class of
- this category is 'auto_ptr' with rather controversive semantics. This
- is probably the reason why there are no other smart pointers included:
- It is hard to find a reasonable consensus what they should do...
-
- In general, I don't see why a 'renew' operator would be necessary.
- Although it wouldn't cost anything for the portions of the code which
- do not use it, it does not solve any problem which cannot be solved
- with the current definition of the language.
- --
- dietmar.kuehl@uni-konstanz.de
- http://www.informatik.uni-konstanz.de/~kuehl
- I am a realistic optimist - that's why I appear to be slightly pessimistic
- ---
- [ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
- Contact address: std-c++-request@ncar.ucar.edu. Moderation policy:
- http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
-